package com.miku.blog.service.impl;

import com.miku.blog.domain.*;
import com.miku.blog.domain.dto.ResourceUserDTO;
import com.miku.blog.domain.pojo.IpAddressesDetail;
import com.miku.blog.domain.pojo.LoginUser;
import com.miku.blog.domain.pojo.ResponseResult;
import com.miku.blog.domain.pojo.SystemConstance;
import com.miku.blog.domain.vo.LoginVo;
import com.miku.blog.domain.vo.RoleVo;
import com.miku.blog.eume.HttpStatusEnum;
import com.miku.blog.service.*;
import com.miku.blog.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;
import java.util.List;
import java.util.Map;


/**
 * @author shkstart
 * @create ${}YEAR-05-25 0:14
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Lazy
    @Autowired
    private AuthenticationManager authenticationManager;
    @Lazy
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private UserLoginInfoService userLoginInfoService;
    @Autowired
    private LikeCountService likeCountService;
    @Autowired
    private ResourceService resourceService;

    @Override
    public ResponseResult login(UserAuth userAuth) {

        UsernamePasswordAuthenticationToken authenticationToken
                = new UsernamePasswordAuthenticationToken(userAuth.getUsername(), userAuth.getPassword());
        Authentication
                authenticate = authenticationManager.authenticate(authenticationToken);

        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        UserAuth user = loginUser.getUserAuth();

        //通过验证后 ,, 判断该用户是否已在别处登录 ,若已在别处登录,则进行下线
        String loginUserKey = redisCache.getCacheObject(GenerateKeyUtils.getRedisUserCacheKey(user.getId()));
        if (StringUtils.hasText(loginUserKey)) {
            redisCache.delCacheObject(loginUserKey);
        }

        //判断该用户是否被禁用
        UserInfo userInfo = userInfoService.getUserInfoByUserId(user.getId());
        if (userInfo.getIsDisable().equals(SystemConstance.IS_DISABLE)) {
            return new ResponseResult(HttpStatusEnum.USER_IS_DISABLE);
        }

        //获取用户的登录信息
        UserLoginInfo loginInfo = userLoginInfoService.getUserLoginInfoByUserId(user.getId());

        //获取用户当前登录的ip地址
        IpAddressesDetail ipAddressesDetail
                = IpAddressesUtils.getIpAddressesDetail(restTemplate);

        //解析访问信息 (浏览器信息,系统信息)
        UserAgentParseUtils.UserAgentParse userAgent
                = UserAgentParseUtils.parseUserAgent(null);

        //设置更新登录信息
        UserUtils.setLoginInfoIpDetail(loginInfo, ipAddressesDetail, userAgent);

        //更新此次登录信息
        userLoginInfoService.updateUserLoginInfo(loginInfo);

        //将加密后的token响应给前端
        String token
                = passwordEncoder.encode(GenerateKeyUtils.generateTokenKey(loginUser));
        token = GenerateKeyUtils.replacePasswordEncodeKey(token);

        //获取用户的角色
        Role role = loginUser.getRole();
        RoleVo roleVo = BeanCopyUtils.copyObjectByType(role, RoleVo.class);

        Integer userAuthId = user.getId();
        //获取用户的文章点赞列表
        List<Integer> articleLikeSet = likeCountService.getLikeCountListByUserIdAndType(userAuthId,SystemConstance.LIKE_COUNT_TYPE_BY_ARTICLE);

        //获取用户的评论点赞列表
        List<Integer> commentLikeSet = likeCountService.getLikeCountListByUserIdAndType(userAuthId,SystemConstance.LIKE_COUNT_TYPE_BY_COMMENT);

        //获取用户的说说点赞列表
        List<Integer> talkLikeSet = likeCountService.getLikeCountListByUserIdAndType(userAuthId,SystemConstance.LIKE_COUNT_TYPE_BY_TALK);

        LoginVo loginVo = BeanCopyUtils.copyObjectByType(userInfo, LoginVo.class);
        loginVo.setUserId(userAuthId)
                .setEmail(user.getEmail())
                .setLoginType(loginInfo.getLoginType())
                .setToken(token)
                .setRoleList(Collections.singletonList(roleVo))
                .setArticleLikeSet(articleLikeSet)
                .setCommentLikeSet(commentLikeSet)
                .setTalkLikeSet(talkLikeSet);

        //生成session (弃用)
//        HttpServletRequest request = HttpUtils.getHttpServletRequest();
//        request.getSession();

        //获取用户的角色的资源列表
        Map<String, List<ResourceUserDTO>> resourceMap
                = resourceService.getResourcesByRoleId(role.getId());

        loginUser.setUserInfo(userInfo)
                .setUserLoginInfo(loginInfo)
                .setResourceMap(resourceMap);

        String redisCacheKey
                = GenerateKeyUtils.generateRedisCacheKey(HttpUtils.getHttpServletRequest(), ipAddressesDetail);

        setRedisCache(redisCacheKey,loginUser);

        return ResponseResult.ok().setData(loginVo);
    }


    private void setRedisCache(String redisCacheKey,LoginUser loginUser){
        redisCache.setCacheObject(redisCacheKey,
                loginUser,
                SystemConstance.REDIS_EXPIRE_TIME,
                SystemConstance.REDIS_TIMEUNIT);
        redisCache.setCacheObject(GenerateKeyUtils.getRedisUserCacheKey(loginUser.getUserAuth().getId()),
                redisCacheKey,
                SystemConstance.REDIS_ID_KEY_EXPIRE_TIME,
                SystemConstance.REDIS_TIMEUNIT);
    }


}
